home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / ObjectTcl-1.1 / OtclClass.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-30  |  37.1 KB  |  1,240 lines

  1. /*  _ __ ___ _
  2.  * | |\ /  /| |  $Id: OtclClass.C,v 1.12 1995/05/25 08:25:47 deans Exp $
  3.  * | | /  / | |  Copyright (C) 1995 IXI Limited.
  4.  * |_|/__/_\|_|  IXI Limited, Cambridge, England.
  5.  *
  6.  * Component   : OtclClass
  7.  *
  8.  * Author      : Dean Sheehan (deans@x.co.uk)
  9.  *
  10.  * Description : Contains the implementation of OtclClass, OtclClassOtcl and
  11.  *               OtclClassCpp. OtclClas is an abstract class. OtclClassOtcl
  12.  *               models classes described in Object Tcl. OtclClassCpp is
  13.  *               abstract and superclassed as a result of C++ code generated
  14.  *               from the CDL processor.
  15.  *
  16.  * License     :
  17.             Object Tcl License & Copyright
  18.             ------------------------------
  19.  
  20. IXI Object Tcl software, both binary and source (hereafter, Software) is copyrighted by IXI Limited (IXI), and ownership remains with IXI. 
  21.  
  22. IXI grants you (herafter, Licensee) a license to use the Software for academic, research and internal business purposes only, without a fee. Licensee may distribute the binary and source code (if required) to third parties provided that the copyright notice and this statement appears on all copies and that no charge is associated with such copies. 
  23.  
  24. Licensee may make derivative works. However, if Licensee distributes any derivative work based on or derived from the Software, then Licensee will (1) notify IXI regarding its distribution of the derivative work, and (2) clearly notify users that such derivative work is a modified version and not the original IXI Object Tcl distributed by IXI. IXI strongly recommends that Licensee provide IXI the right to incorporate such modifications into future releases of the Software under these license terms. 
  25.  
  26. Any Licensee wishing to make commercial use of the Software should contact IXI, to negotiate an appropriate license for such commercial use. Commercial use includes (1) integration of all or part of the source code into a product for sale or license by or on behalf of Licensee to third parties, or (2) distribution of the binary code or source code to third parties that need it to utilize a commercial product sold or licensed by or on behalf of Licensee. 
  27.  
  28. IXI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. IXI SHALL NOT BE LIABLE FOR ANY DAMAGES WHATSOEVER SUFFERED BY THE USERS OF THIS SOFTWARE. 
  29.  
  30. Copyright (C) 1995, IXI Limited 
  31.  
  32. By using or copying this Software, Licensee agrees to abide by the copyright law and all other applicable laws of England and the U.S., including, but not limited to, export control laws, and the terms of this license. IXI shall have the right to terminate this license immediately by written notice upon Licensee's breach of, or non-compliance with, any of its terms. Licensee may be held legally responsible for any copyright infringement that is caused or encouraged by Licensee's failure to abide by the terms of this license. 
  33.  
  34. Comments and questions are welcome and can be sent to
  35. otcl@x.co.uk 
  36.  
  37. For more information on copyright and licensing issues, contact: 
  38. Legal Department, IXI Limited, Vision Park, Cambridge CB4 4ZR,
  39. ENGLAND. 
  40.  
  41.  *
  42.  */
  43.  
  44. // Tcl Includes
  45. #include <tclInt.h>
  46.  
  47. // Local Includes
  48. #include "OtclClass.H"
  49. #include "OtclMethod.H"
  50. #include "OtclAttribute.H"
  51. #include "OtclObject.H"
  52. #include "OtclObjMgr.H"
  53. #include "OtclPart.H"
  54.  
  55. // Class Attribute Definitions
  56. OtclClassCpp *OtclClassCpp::head = NULL;
  57. OtclClassCpp *OtclClassCpp::tail = NULL;
  58. Tcl_HashTable OtclClassOtcl::commandTable;
  59.  
  60. OtclClass::OtclClass (char *n)
  61. {
  62.    name = strdup(n);
  63. }
  64.  
  65. OtclClass::~OtclClass ()
  66. {
  67.    if (Otcl::tclInterp != NULL)
  68.       Tcl_DeleteCommand(Otcl::tclInterp,name);
  69.    free(name);
  70. }
  71.  
  72.  
  73.  
  74.  
  75. OtclClassOtcl::OtclClassOtcl (char *name, Otcl *parent) :
  76.    OtclClass(name)
  77. {
  78.    noOfSuperclasses = 0;
  79.    otcl = parent;
  80.    Tcl_InitHashTable(&instanceMethods,TCL_STRING_KEYS);
  81.    Tcl_InitHashTable(&classMethods,TCL_STRING_KEYS);
  82.    Tcl_InitHashTable(&classAttributes,TCL_STRING_KEYS);
  83.    Tcl_InitHashTable(&instanceAttributeTemplates,TCL_STRING_KEYS);
  84.    otclConstructorMethod = NULL;
  85.    otclDestructorMethod = NULL;
  86.    complete = OTCL_FALSE;
  87. }
  88.  
  89. OtclClassOtcl::~OtclClassOtcl ()
  90. {
  91.    // free instances! Not sure it would require a list of instances
  92.    // which would be expensive to maintain on creation / deletion of objects,
  93.  
  94.    // If I keep the objects in command I could put in a command delete
  95.    // proc that deletes the object. This way objs would be cleaned
  96.    // up if the interp is deleted.
  97.  
  98.    Tcl_HashEntry *entry;
  99.    Tcl_HashSearch search;
  100.  
  101.    // Clean up methods
  102.    for (entry = Tcl_FirstHashEntry(&instanceMethods,&search);
  103.         entry != NULL;
  104.         entry = Tcl_NextHashEntry(&search))
  105.    {
  106.       delete ((OtclMethod*)Tcl_GetHashValue(entry));
  107.    }
  108.    Tcl_DeleteHashTable(&instanceMethods);
  109.    for (entry = Tcl_FirstHashEntry(&classMethods,&search);
  110.         entry != NULL;
  111.         entry = Tcl_NextHashEntry(&search))
  112.    {
  113.       delete ((OtclMethod*)Tcl_GetHashValue(entry));
  114.    }
  115.    Tcl_DeleteHashTable(&classMethods);
  116.  
  117.  
  118.    // Cleanup classAttributes
  119.    for (entry = Tcl_FirstHashEntry(&classAttributes,&search);
  120.         entry != NULL;
  121.         entry = Tcl_NextHashEntry(&search))
  122.    {
  123.       delete ((OtclAttribute*)Tcl_GetHashValue(entry));
  124.    }
  125.    Tcl_DeleteHashTable(&classAttributes);
  126.  
  127.    // Cleanup instance attributes templates
  128.    for (entry = Tcl_FirstHashEntry(&instanceAttributeTemplates,&search);
  129.         entry != NULL;
  130.         entry = Tcl_NextHashEntry(&search))
  131.    {
  132.       delete ((OtclAttributeTemplate*)Tcl_GetHashValue(entry));
  133.    }
  134.    Tcl_DeleteHashTable(&instanceAttributeTemplates);
  135.  
  136.    if (otclConstructorMethod != NULL)
  137.    {
  138.       delete otclConstructorMethod;
  139.    }
  140.  
  141.    if (otclDestructorMethod)
  142.    {
  143.       delete otclDestructorMethod;
  144.    }
  145. }
  146.  
  147. int OtclClassOtcl::parseInterface (Tcl_Interp *interp, int argc, char *argv[])
  148. {
  149.    ARGC_RANGE(3,5)
  150.    {
  151.       return Otcl::setTclError(interp,ARGS_CLASS_INTERFACE_ERR);
  152.    }
  153.  
  154.    if (argc > 3)
  155.    {
  156.      // Should have an "-isA" at argv[2] and a class list at argv[3]
  157.      if (strcmp(argv[2],"-isA") != 0)
  158.      {
  159.          return Otcl::setTclError(interp,ARGS_CLASS_INTERFACE_ERR);
  160.      }
  161.  
  162.      if (argc != 5)
  163.      {
  164.         // We are missing the class list
  165.         return Otcl::setTclError(interp,ARGS_CLASS_INTERFACE_ERR);
  166.      }
  167.  
  168.      if (parseIsAList(interp,argv[3]) != TCL_OK)
  169.      {
  170.         return TCL_ERROR;   
  171.      }
  172.    }
  173.  
  174.    placeInterfaceCommandsInScope(interp);
  175.  
  176.    int returnCode = Tcl_Eval(interp,argv[argc-1]);
  177.  
  178.    removeInterfaceCommandsFromScope(interp);
  179.  
  180.    return returnCode;
  181. }
  182.  
  183. void OtclClassOtcl::placeInterfaceCommandsInScope (Tcl_Interp *interp)
  184. {
  185.    // Need to take all of the global commands out and place our news ones
  186.    // in. This is the easiest way I can see of doing this. Copy out
  187.    // the commands hash table from the interp and initialise a new one in
  188.    // its place.
  189.    memcpy(&commandTable,&((Interp*)interp)->commandTable,sizeof(Tcl_HashTable));
  190.    Tcl_InitHashTable(&((Interp*)interp)->commandTable,TCL_STRING_KEYS);
  191.  
  192.    // Install new commands
  193.    Tcl_CreateCommand(interp,INSTANCE_METHOD_INTERFACE_CMD,
  194.                      OtclClassOtcl::instanceMethodInterfaceCmd,
  195.                      (ClientData)this,(Tcl_CmdDeleteProc*)NULL);
  196.  
  197.    Tcl_CreateCommand(interp,CLASS_METHOD_INTERFACE_CMD,
  198.                      OtclClassOtcl::classMethodInterfaceCmd,
  199.                      (ClientData)this,(Tcl_CmdDeleteProc*)NULL);
  200.  
  201.    Tcl_CreateCommand(interp,CONSTRUCTOR_INTERFACE_CMD,
  202.                      OtclClassOtcl::constructorInterfaceCmd,
  203.                      (ClientData)this,(Tcl_CmdDeleteProc*)NULL);
  204. }
  205.  
  206. void OtclClassOtcl::removeInterfaceCommandsFromScope (Tcl_Interp *interp)
  207. {
  208.    // Remove new commands
  209.    Tcl_DeleteCommand(interp,INSTANCE_METHOD_INTERFACE_CMD);
  210.    Tcl_DeleteCommand(interp,CLASS_METHOD_INTERFACE_CMD);
  211.    Tcl_DeleteCommand(interp,CONSTRUCTOR_INTERFACE_CMD);
  212.  
  213.    // Delete, cleanup, old the hash table
  214.    Tcl_DeleteHashTable(&((Interp*)interp)->commandTable);
  215.  
  216.    // Place old commands back in
  217.    memcpy(&((Interp*)interp)->commandTable,&commandTable,sizeof(Tcl_HashTable));
  218. }
  219.  
  220. int OtclClassOtcl::instanceMethodInterfaceCmd (ClientData cd,
  221.                                                Tcl_Interp *interp,
  222.                                                int argc, char *argv[])
  223. {
  224.    OtclClassOtcl *otclClassOtcl = (OtclClassOtcl*)cd;
  225.    return otclClassOtcl->instanceMethodInterface(interp,argc,argv);
  226. }
  227.  
  228. int OtclClassOtcl::classMethodInterfaceCmd (ClientData cd,
  229.                                             Tcl_Interp *interp,
  230.                                             int argc, char *argv[])
  231. {
  232.    OtclClassOtcl *otclClassOtcl = (OtclClassOtcl*)cd;
  233.    return otclClassOtcl->classMethodInterface(interp,argc,argv);
  234. }
  235.  
  236. int OtclClassOtcl::constructorInterfaceCmd (ClientData cd,
  237.                                             Tcl_Interp *interp,
  238.                                             int argc, char *argv[])
  239. {
  240.    OtclClassOtcl *otclClassOtcl = (OtclClassOtcl*)cd;
  241.    return otclClassOtcl->constructorInterface(interp,argc,argv);
  242. }
  243.  
  244. int OtclClassOtcl::instanceMethodInterface (Tcl_Interp *interp,
  245.                                             int argc, char *argv[])
  246. {
  247.    ARGC_VALUE(3)
  248.    {
  249.       return Otcl::setTclError(interp,ARGS_METHOD_INTERFACE_ERR);
  250.    }
  251.  
  252.    if (validMethodName(argv[1]) == OTCL_FALSE)
  253.    {
  254.      return Otcl::setTclError(interp,BAD_NAME_FOR_INST_METHOD_ERR,argv[1]);
  255.    }
  256.  
  257.    int newEntry;
  258.    OtclMethod *otclMethod;
  259.    Tcl_HashEntry *hashEntry = Tcl_FindHashEntry(&classMethods,argv[1]);
  260.    if (hashEntry != NULL)
  261.    {
  262.       Otcl::setTclResult(interp,METHOD_INTERFACE_DUPLICATED_ERR,argv[1],name);
  263.       return TCL_ERROR;
  264.    }
  265.    hashEntry = Tcl_CreateHashEntry(&instanceMethods,argv[1],&newEntry);
  266.    if (newEntry == 1)
  267.    {
  268.       otclMethod = new OtclInstanceMethod(argv[1],OtclMethod::PUBLIC,this);
  269.       Tcl_SetHashValue(hashEntry,otclMethod);
  270.    }
  271.    else
  272.    {
  273.       Otcl::setTclResult(interp,METHOD_INTERFACE_DUPLICATED_ERR,argv[1],name);
  274.       return TCL_ERROR;
  275.    }
  276.  
  277.    return otclMethod->setFormalArgs(interp,argv[2]);
  278. }
  279.  
  280. int OtclClassOtcl::classMethodInterface (Tcl_Interp *interp,
  281.                                          int argc, char *argv[])
  282. {
  283.    ARGC_VALUE(3)
  284.    {
  285.       return Otcl::setTclError(interp,ARGS_CLASS_METHOD_INTERFACE_ERR);  
  286.    }
  287.  
  288.    if (validMethodName(argv[1]) == OTCL_FALSE)
  289.    {
  290.       return Otcl::setTclError(interp,BAD_NAME_FOR_CLASS_METHOD_ERR,argv[1]);
  291.    }
  292.  
  293.    int newEntry;
  294.    OtclMethod *otclMethod;
  295.    Tcl_HashEntry *hashEntry = Tcl_FindHashEntry(&instanceMethods,argv[1]);
  296.    if (hashEntry != NULL)
  297.    {
  298.       Otcl::setTclResult(interp,METHOD_INTERFACE_DUPLICATED_ERR,argv[1],name);
  299.       return TCL_ERROR;
  300.    }
  301.    hashEntry = Tcl_CreateHashEntry(&classMethods,argv[1],&newEntry);
  302.    if (newEntry == 1)
  303.    {
  304.       otclMethod = new OtclClassMethod(argv[1],OtclMethod::PUBLIC,this);
  305.       Tcl_SetHashValue(hashEntry,otclMethod);
  306.    }
  307.    else
  308.    {
  309.       Otcl::setTclResult(interp,METHOD_INTERFACE_DUPLICATED_ERR,argv[1],name);
  310.       return TCL_ERROR;
  311.    }
  312.  
  313.    return otclMethod->setFormalArgs(interp,argv[2]);
  314. }
  315.  
  316. int OtclClassOtcl::constructorInterface (Tcl_Interp *interp,
  317.                                          int argc, char *argv[])
  318. {
  319.    ARGC_VALUE(2)
  320.    {
  321.       return Otcl::setTclError(interp,ARGS_CONSTRUCTOR_INTERFACE_ERR);
  322.    }
  323.  
  324.    if (otclConstructorMethod == NULL)
  325.    {
  326.       otclConstructorMethod = new OtclConstructorMethod(this);
  327.    }
  328.    else
  329.    {
  330.       Otcl::setTclResult(interp,METHOD_INTERFACE_DUPLICATED_ERR,argv[0],name);
  331.       return TCL_ERROR;
  332.    }
  333.  
  334.    return otclConstructorMethod->setFormalArgs(interp,argv[1]);
  335. }
  336.  
  337. int OtclClassOtcl::parseImplementation (Tcl_Interp *interp,
  338.                                         int argc, char *argv[])
  339. {
  340.    ARGC_VALUE(3)
  341.    {
  342.       return Otcl::setTclError(interp,ARGS_CLASS_IMPLEMENTATION_ERR);
  343.    }
  344.  
  345.    if (complete == OTCL_TRUE)
  346.    {
  347.       Otcl::setTclResult(interp,CLASS_ALREADY_COMPLETED_ERR,name);
  348.       return TCL_ERROR;
  349.    }
  350.  
  351.    placeImplementationCommandsInScope(interp);
  352.  
  353.    int returnCode = Tcl_Eval(interp,argv[argc-1]);
  354.  
  355.    removeImplementationCommandsFromScope(interp);
  356.  
  357.    if (returnCode != TCL_OK)
  358.    {
  359.       return TCL_ERROR;
  360.    }
  361.  
  362.    if (checkClassCompleteness(interp) == TCL_ERROR)
  363.    {
  364.       return TCL_ERROR;
  365.    }
  366.  
  367.    addClassCommand(interp);
  368.  
  369.    complete = OTCL_TRUE;
  370.  
  371.    return returnCode;
  372. }
  373.  
  374. int OtclClassOtcl::checkClassCompleteness (Tcl_Interp *interp)
  375. {
  376.    Tcl_HashEntry *entry;
  377.    Tcl_HashSearch search;
  378.    OtclMethod *method;
  379.    char *paramName;
  380.  
  381.    for (entry = Tcl_FirstHashEntry(&instanceMethods,&search);
  382.         entry != NULL;
  383.         entry = Tcl_NextHashEntry(&search))
  384.    {
  385.       method = (OtclMethod*)Tcl_GetHashValue(entry);
  386.  
  387.       // Check method completed
  388.       if (method->hasBody() == OTCL_FALSE)
  389.       {
  390.          return Otcl::setTclError(interp,INST_METHOD_NOT_COMPLETED_ERR,
  391.                                   Tcl_GetHashKey(&instanceMethods,entry),
  392.                                   name);
  393.       }
  394.  
  395.       // Check method doesn't have any param names the same as attribute's
  396.       for (paramName = method->giveFirstFormalArgName();
  397.            paramName != NULL;
  398.            paramName = method->giveNextFormalArgName())
  399.       {
  400.          if (Tcl_FindHashEntry(&instanceAttributeTemplates,paramName) != NULL ||
  401.              Tcl_FindHashEntry(&classAttributes,paramName) != NULL)
  402.          {
  403.             return Otcl::setTclError(interp,FORMAL_ARG_ATTRIB_CLASH_ERR,
  404.                                      Tcl_GetHashKey(&instanceMethods,entry),
  405.                                      name,paramName);
  406.          }
  407.       }
  408.       
  409.    }
  410.    for (entry = Tcl_FirstHashEntry(&classMethods,&search);
  411.         entry != NULL;
  412.         entry = Tcl_NextHashEntry(&search))
  413.    {
  414.       method = (OtclMethod*)Tcl_GetHashValue(entry);
  415.       if (method->hasBody() == OTCL_FALSE)
  416.       {
  417.          return Otcl::setTclError(interp,CLASS_METHOD_NOT_COMPLETED_ERR,
  418.                                   Tcl_GetHashKey(&classMethods,entry),
  419.                                   name);
  420.       }
  421.  
  422.       // Check method doesn't have any param names the same as attribute's
  423.       for (paramName = method->giveFirstFormalArgName();
  424.            paramName != NULL;
  425.            paramName = method->giveNextFormalArgName())
  426.       {
  427.          if (Tcl_FindHashEntry(&classAttributes,paramName) != NULL)
  428.          {
  429.             return Otcl::setTclError(interp,FORMAL_ARG_ATTRIB_CLASH_ERR,
  430.                                      Tcl_GetHashKey(&instanceMethods,entry),
  431.                                      name,paramName);
  432.          }
  433.       }
  434.  
  435.    }
  436.    if (otclConstructorMethod != NULL)
  437.    {
  438.       if (otclConstructorMethod->hasBody() == OTCL_FALSE)
  439.       {
  440.          return Otcl::setTclError(interp,INST_METHOD_NOT_COMPLETED_ERR,
  441.                                   OTCL_CONSTRUCTOR_METHOD_NAME,name);
  442.       }
  443.       
  444.       // Check method doesn't have any param names the same as attribute's
  445.       for (paramName = otclConstructorMethod->giveFirstFormalArgName();
  446.            paramName != NULL;
  447.            paramName = otclConstructorMethod->giveNextFormalArgName())
  448.       {
  449.          if (Tcl_FindHashEntry(&instanceAttributeTemplates,paramName) != NULL ||
  450.              Tcl_FindHashEntry(&classAttributes,paramName) != NULL)
  451.          {
  452.             return Otcl::setTclError(interp,FORMAL_ARG_ATTRIB_CLASH_ERR,
  453.                                      OTCL_CONSTRUCTOR_METHOD_NAME,
  454.                                      name,paramName);
  455.          }
  456.       }
  457.    }
  458.  
  459.    return TCL_OK;
  460. }
  461.  
  462. void OtclClassOtcl::addClassCommand (Tcl_Interp *interp)
  463. {
  464.    Tcl_CreateCommand(interp,name,Otcl::classCmd,
  465.                      (ClientData)this,(Tcl_CmdDeleteProc*)NULL);
  466. }
  467.  
  468. void OtclClassOtcl::placeImplementationCommandsInScope (Tcl_Interp *interp)
  469. {
  470.    memcpy(&commandTable,&((Interp*)interp)->commandTable,sizeof(Tcl_HashTable));
  471.    Tcl_InitHashTable(&((Interp*)interp)->commandTable,TCL_STRING_KEYS);
  472.  
  473.    Tcl_CreateCommand(interp,INSTANCE_METHOD_IMPLEMENTATION_CMD,
  474.                      OtclClassOtcl::instanceMethodImplementationCmd,
  475.                      (ClientData)this,(Tcl_CmdDeleteProc*)NULL);
  476.  
  477.    Tcl_CreateCommand(interp,CLASS_METHOD_IMPLEMENTATION_CMD,
  478.                      OtclClassOtcl::classMethodImplementationCmd,
  479.                      (ClientData)this,(Tcl_CmdDeleteProc*)NULL);
  480.  
  481.    Tcl_CreateCommand(interp,CONSTRUCTOR_IMPLEMENTATION_CMD,
  482.                      OtclClassOtcl::constructorImplementationCmd,
  483.                      (ClientData)this,(Tcl_CmdDeleteProc*)NULL);
  484.  
  485.    Tcl_CreateCommand(interp,DESTRUCTOR_IMPLEMENTATION_CMD,
  486.                      OtclClassOtcl::destructorImplementationCmd,
  487.                      (ClientData)this,(Tcl_CmdDeleteProc*)NULL);
  488.  
  489.    Tcl_CreateCommand(interp,INSTANCE_ATTRIBUTE_CMD,
  490.                      OtclClassOtcl::instanceAttributeCmd,
  491.                      (ClientData)this,(Tcl_CmdDeleteProc*)NULL);
  492.  
  493.    Tcl_CreateCommand(interp,CLASS_ATTRIBUTE_CMD,
  494.                      OtclClassOtcl::classAttributeCmd,
  495.                      (ClientData)this,(Tcl_CmdDeleteProc*)NULL);
  496.  
  497. }
  498.  
  499. void OtclClassOtcl::removeImplementationCommandsFromScope (Tcl_Interp *interp)
  500. {
  501.    Tcl_DeleteCommand(interp,INSTANCE_METHOD_IMPLEMENTATION_CMD);
  502.    Tcl_DeleteCommand(interp,CLASS_METHOD_IMPLEMENTATION_CMD);
  503.    Tcl_DeleteCommand(interp,CONSTRUCTOR_IMPLEMENTATION_CMD);
  504.    Tcl_DeleteCommand(interp,DESTRUCTOR_IMPLEMENTATION_CMD);
  505.    Tcl_DeleteCommand(interp,INSTANCE_ATTRIBUTE_CMD);
  506.    Tcl_DeleteCommand(interp,CLASS_ATTRIBUTE_CMD);
  507.  
  508.    // Delete, cleanup, old the hash table
  509.    Tcl_DeleteHashTable(&((Interp*)interp)->commandTable);
  510.  
  511.    // Place old commands back in
  512.    memcpy(&((Interp*)interp)->commandTable,&commandTable,sizeof(Tcl_HashTable));
  513. }
  514.  
  515. int OtclClassOtcl::shouldDelete (void)
  516. {
  517.    return OTCL_TRUE;
  518. }
  519.  
  520. int OtclClassOtcl::parseIsAList (Tcl_Interp *interp, char *classList)
  521. {
  522.    
  523.    int listArgc;
  524.    char **listArgv;
  525.    if (Tcl_SplitList(interp,classList,&listArgc,&listArgv) != TCL_OK)
  526.    {
  527.       return TCL_ERROR;
  528.    }
  529.  
  530.    if (listArgc > MAX_SUPERCLASSES)
  531.    {
  532.       Otcl::setTclResult(interp,TOO_MANY_SUPERCLASSES_ERR,name,
  533.                          MAX_SUPERCLASSES);
  534.       free((char*)listArgv);
  535.       return TCL_ERROR;
  536.    }
  537.  
  538.    if (listArgc== 0)
  539.    {
  540.       Otcl::setTclResult(interp,NO_CLASSES_IN_ISA_LIST_ERR,name);
  541.       free((char*)listArgv);
  542.       return TCL_ERROR;
  543.    }
  544.  
  545.    noOfSuperclasses = listArgc;
  546.    int i;
  547.    int j;
  548.    for (i = 0; i < listArgc; i++)
  549.    {
  550.       superclass[i] = otcl->giveOtclClass(listArgv[i]);
  551.       if (superclass[i] == NULL || superclass[i]->isComplete() == OTCL_FALSE)
  552.       {
  553.          Otcl::setTclResult(interp,SUPERCLASS_NOT_KNOWN_ERR,name,listArgv[i]);
  554.          free((char*)listArgv);
  555.          return TCL_ERROR;
  556.       }
  557.       for (j = 0; j < i; j++)
  558.       {
  559.          if (superclass[j] == superclass[i])
  560.          {
  561.             Otcl::setTclResult(interp,SUPERCLASS_DUPLICATION_ERR,
  562.                                listArgv[i],name);
  563.             free((char*)listArgv);
  564.             return TCL_ERROR;
  565.          }
  566.       }
  567.    }
  568.  
  569.    free((char*)listArgv);
  570.    return TCL_OK;
  571. }
  572.  
  573. int OtclClassOtcl::instanceMethodImplementationCmd (ClientData cd,
  574.                                                     Tcl_Interp *interp,
  575.                                                     int argc, char *argv[])
  576. {
  577.    OtclClassOtcl *otclClassOtcl = (OtclClassOtcl*)cd;
  578.    return otclClassOtcl->instanceMethodImplementation(interp,argc,argv);
  579. }
  580.  
  581. int OtclClassOtcl::classMethodImplementationCmd (ClientData cd,
  582.                                                  Tcl_Interp *interp,
  583.                                                  int argc, char *argv[])
  584. {
  585.    OtclClassOtcl *otclClassOtcl = (OtclClassOtcl*)cd;
  586.    return otclClassOtcl->classMethodImplementation(interp,argc,argv);
  587. }
  588.  
  589. int OtclClassOtcl::constructorImplementationCmd (ClientData cd,
  590.                                                  Tcl_Interp *interp,
  591.                                                  int argc, char *argv[])
  592. {
  593.    OtclClassOtcl *otclClassOtcl = (OtclClassOtcl*)cd;
  594.    return otclClassOtcl->constructorImplementation(interp,argc,argv);
  595. }
  596.  
  597. int OtclClassOtcl::destructorImplementationCmd (ClientData cd,
  598.                                                 Tcl_Interp *interp,
  599.                                                 int argc, char *argv[])
  600. {
  601.    OtclClassOtcl *otclClassOtcl = (OtclClassOtcl*)cd;
  602.    return otclClassOtcl->destructorImplementation(interp,argc,argv);
  603. }
  604.  
  605. int OtclClassOtcl::instanceAttributeCmd (ClientData cd,
  606.                                          Tcl_Interp *interp,
  607.                                          int argc, char *argv[])
  608. {
  609.    OtclClassOtcl *otclClassOtcl = (OtclClassOtcl*)cd;
  610.    return otclClassOtcl->instanceAttribute(interp,argc,argv);
  611. }
  612.  
  613. int OtclClassOtcl::classAttributeCmd (ClientData cd,
  614.                                       Tcl_Interp *interp,
  615.                                       int argc, char *argv[])
  616. {
  617.    OtclClassOtcl *otclClassOtcl = (OtclClassOtcl*)cd;
  618.    return otclClassOtcl->classAttribute(interp,argc,argv);
  619. }
  620.  
  621. int OtclClassOtcl::classMethod (Tcl_Interp *interp, int argc, char *argv[])
  622. {
  623.    ARGC_MIN(2)
  624.    {
  625.       return Otcl::setTclError(interp,ARGS_CLASS_METHOD_EXE_ERR);
  626.    }
  627.  
  628.    // Find the method name as argument 2 (argv[1])
  629.    Tcl_HashEntry *hashEntry = Tcl_FindHashEntry(&classMethods,argv[1]);
  630.    if (hashEntry == NULL)
  631.    {
  632.       Otcl::setTclResult(interp,CLASS_METHOD_NOT_FOUND_ERR,argv[1],name);
  633.       return TCL_ERROR;
  634.    }
  635.  
  636.    OtclClassMethod *method = (OtclClassMethod*)Tcl_GetHashValue(hashEntry);
  637.    if (method->isAccessible(interp) == OTCL_FALSE)
  638.    {
  639.       Otcl::setTclResult(interp,PRIVATE_METHOD_NO_ACCESS_ERR,argv[1],name);
  640.       return TCL_ERROR;
  641.    }
  642.  
  643.    createClassScope(interp);
  644.    int resultCode = method->execute(interp,argc-2,(argc > 2 ? &argv[2] : NULL));
  645.    destroyClassScope (interp);
  646.  
  647.    return resultCode;
  648. }
  649.  
  650. int OtclClassOtcl::instanceMethodImplementation (Tcl_Interp *interp,
  651.                                                  int argc, char *argv[])
  652. {
  653.    ARGC_VALUE(4)
  654.    {
  655.       return Otcl::setTclError(interp,ARGS_METHOD_IMPLEMENTATION_ERR);
  656.    }
  657.  
  658.    if (validMethodName(argv[1]) == OTCL_FALSE)
  659.    {
  660.       return Otcl::setTclError(interp,BAD_NAME_FOR_INST_METHOD_ERR,argv[1]);
  661.    }
  662.  
  663.    int newEntry;
  664.    Tcl_HashEntry *hashEntry = Tcl_FindHashEntry(&classMethods,argv[1]);
  665.    if (hashEntry != NULL)
  666.    {
  667.       OtclMethod *method = (OtclMethod*)Tcl_GetHashValue(hashEntry);
  668.       if (method->hasBody() == OTCL_TRUE)
  669.       {
  670.          return Otcl::setTclError(interp,BODY_ALREADY_SPECIFIED_ERR,argv[1]);
  671.       }
  672.       return Otcl::setTclError(interp,IMP_AS_INST_INT_AS_CLASS_ERR,argv[1]);
  673.    }
  674.    OtclMethod *otclMethod;
  675.    hashEntry = Tcl_CreateHashEntry(&instanceMethods,argv[1],&newEntry);
  676.    if (newEntry == 1)
  677.    {
  678.       otclMethod = new OtclInstanceMethod(argv[1],OtclMethod::PRIVATE,this);
  679.       Tcl_SetHashValue(hashEntry,otclMethod);
  680.    }
  681.    else
  682.    {
  683.       otclMethod = (OtclMethod*)Tcl_GetHashValue(hashEntry);
  684.    }
  685.  
  686.    int returnCode = otclMethod->setFormalArgs(interp,argv[2]);
  687.    if (returnCode != TCL_OK)
  688.    {
  689.       return returnCode;
  690.    }
  691.    return otclMethod->setBody(interp,argv[3]);
  692. }
  693.  
  694. int OtclClassOtcl::classMethodImplementation (Tcl_Interp *interp,
  695.                                               int argc, char *argv[])
  696. {
  697.    ARGC_VALUE(4)
  698.    {
  699.       return Otcl::setTclError(interp,ARGS_CLASS_METHOD_IMPLEMENTATION_ERR);
  700.    }
  701.  
  702.    if (validMethodName(argv[1]) == OTCL_FALSE)
  703.    {
  704.       return Otcl::setTclError(interp,BAD_NAME_FOR_CLASS_METHOD_ERR,argv[1]);
  705.    }
  706.  
  707.    int newEntry;
  708.    Tcl_HashEntry *hashEntry = Tcl_FindHashEntry(&instanceMethods,argv[1]);
  709.    if (hashEntry != NULL)
  710.    {
  711.       OtclMethod *method = (OtclMethod*)Tcl_GetHashValue(hashEntry);
  712.       if (method->hasBody() == OTCL_TRUE)
  713.       {
  714.          return Otcl::setTclError(interp,BODY_ALREADY_SPECIFIED_ERR,argv[1]);
  715.       }
  716.       return Otcl::setTclError(interp,IMP_AS_CLASS_INT_AS_INST_ERR,argv[1]);
  717.    }
  718.  
  719.    OtclMethod *otclMethod;
  720.    hashEntry = Tcl_CreateHashEntry(&classMethods,argv[1],&newEntry);
  721.    if (newEntry == 1)
  722.    {
  723.       otclMethod = new OtclClassMethod(argv[1],OtclMethod::PRIVATE,this);
  724.       Tcl_SetHashValue(hashEntry,otclMethod);
  725.    }
  726.    else
  727.    {
  728.       otclMethod = (OtclMethod*)Tcl_GetHashValue(hashEntry);
  729.    }
  730.  
  731.    int returnCode = otclMethod->setFormalArgs(interp,argv[2]);
  732.    if (returnCode != TCL_OK)
  733.    {
  734.       return returnCode;
  735.    }
  736.    return otclMethod->setBody(interp,argv[3]);
  737. }
  738.  
  739. int OtclClassOtcl::constructorImplementation (Tcl_Interp *interp,
  740.                                               int argc, char *argv[])
  741. {
  742.    ARGC_VALUE(4)
  743.    {
  744.       return Otcl::setTclError(interp,ARGS_CONSTRUCTOR_IMPLEMENTATION_ERR);
  745.    }
  746.  
  747.    if (otclConstructorMethod == NULL)
  748.    {
  749.       Otcl::setTclResult(interp,CONSTRUCTOR_NOT_INTERFACED_ERR,name);
  750.       return TCL_ERROR;
  751.    }
  752.  
  753.    int returnCode = otclConstructorMethod->setFormalArgs(interp,argv[1]);
  754.    if (returnCode != TCL_OK)
  755.    {
  756.       return returnCode;
  757.    }
  758.    returnCode = otclConstructorMethod->setParentConstructors(interp,argv[2]);
  759.    if (returnCode != TCL_OK)
  760.    {
  761.       return returnCode;
  762.    }
  763.    return otclConstructorMethod->setBody(interp,argv[3]);
  764. }
  765.  
  766. int OtclClassOtcl::destructorImplementation (Tcl_Interp *interp,
  767.                                              int argc, char *argv[])
  768. {
  769.    ARGC_VALUE(2)
  770.    {
  771.       return Otcl::setTclError(interp,ARGS_DESTRUCTOR_ERR);
  772.    }
  773.  
  774.    if (otclDestructorMethod != NULL)
  775.    {
  776.       Otcl::setTclResult(interp,REDEFINED_DESTRUCTOR_ERR,name);
  777.       return TCL_ERROR;
  778.    }
  779.  
  780.    otclDestructorMethod = new OtclDestructorMethod(this);
  781.  
  782.    return otclDestructorMethod->setBody(interp,argv[1]);
  783. }
  784.  
  785. int OtclClassOtcl::instanceAttribute (Tcl_Interp *interp,
  786.                                       int argc, char *argv[])
  787. {
  788.    ARGC_RANGE(2,3)
  789.    {
  790.       return Otcl::setTclError(interp,ARGS_ATTRIBUTE_ERR);
  791.    }
  792.  
  793.    if (strcmp(argv[1],OTCL_SELF_ATTRIBUTE) == 0)
  794.    {
  795.       return Otcl::setTclError(interp,ATTRIB_CANNOT_BE_CALLED_ERR,argv[1]);
  796.    }
  797.  
  798.    int isArray = OTCL_FALSE;
  799.    // check to see if it is an array attribute
  800.    if (argv[1][strlen(argv[1])-1] == ')' &&
  801.        argv[1][strlen(argv[1])-2] == '(')
  802.    {
  803.       argv[1][strlen(argv[1])-2] = '\0';
  804.       isArray = OTCL_TRUE;
  805.    }
  806.  
  807.    int newEntry;
  808.    Tcl_HashEntry *hashEntry = Tcl_FindHashEntry(&classAttributes,argv[1]);
  809.    if (hashEntry != NULL)
  810.    {
  811.       Otcl::setTclResult(interp,INST_ATTRIB_CLASH_CLASS_ERR,argv[1],name);
  812.       return TCL_ERROR;
  813.    }
  814.  
  815.    hashEntry = Tcl_CreateHashEntry(&instanceAttributeTemplates,
  816.                                    argv[1],&newEntry);
  817.    OtclAttributeTemplate *temp;
  818.    if (newEntry == 1)
  819.    {
  820.       temp = new OtclAttributeTemplate(interp,isArray,(argc == 3? argv[2] : NULL));
  821.       Tcl_SetHashValue(hashEntry,temp);
  822.    }
  823.    else
  824.    {
  825.       Otcl::setTclResult(interp,INST_ATTRIB_CLASH_ERR,argv[1],name);
  826.       return TCL_ERROR;
  827.    }
  828.  
  829.    return TCL_OK;
  830. }
  831.  
  832. int OtclClassOtcl::classAttribute (Tcl_Interp *interp,
  833.                                    int argc, char *argv[])
  834. {
  835.    ARGC_VALUE(3)
  836.    {
  837.       return Otcl::setTclError(interp,ARGS_CLASS_ATTRIBUTE_ERR);
  838.    }
  839.  
  840.    if (strcmp(argv[1],OTCL_SELF_ATTRIBUTE) == 0)
  841.    {
  842.       return Otcl::setTclError(interp,ATTRIB_CANNOT_BE_CALLED_ERR,argv[1]);
  843.    }
  844.  
  845.    int isArray = OTCL_FALSE;
  846.    // check to see if it is an array attribute
  847.    if (argv[1][strlen(argv[1])-1] == ')' &&
  848.        argv[1][strlen(argv[1])-2] == '(')
  849.    {
  850.       argv[1][strlen(argv[1])-2] = '\0';
  851.       isArray = OTCL_TRUE;
  852.    }
  853.  
  854.    int newEntry;
  855.    Tcl_HashEntry *hashEntry = Tcl_FindHashEntry(&instanceAttributeTemplates,
  856.                                                 argv[1]);
  857.    if (hashEntry != NULL)
  858.    {
  859.       Otcl::setTclResult(interp,CLASS_ATTRIB_CLASH_INST_ERR,argv[1],name);
  860.       return TCL_ERROR;
  861.    }
  862.  
  863.    hashEntry = Tcl_CreateHashEntry(&classAttributes,argv[1],&newEntry);
  864.    OtclAttribute *attribute;
  865.    if (newEntry == 1)
  866.    {
  867.       attribute = new OtclAttribute(hashEntry,isArray,argv[2],interp);
  868.       Tcl_SetHashValue(hashEntry,attribute);
  869.    }
  870.    else
  871.    {
  872.       Otcl::setTclResult(interp,CLASS_ATTRIB_CLASH_ERR,argv[1],name);
  873.       return TCL_ERROR;
  874.  
  875.    }
  876.  
  877.    return TCL_OK;
  878. }
  879.  
  880. int OtclClassOtcl::giveIndexOfSuperclass (char *n)
  881. {
  882.    for (int s = 0; s < noOfSuperclasses; s++)
  883.    {
  884.       if (strcmp(superclass[s]->giveName(),n) == 0)
  885.       {
  886.          return s;
  887.       }
  888.    }
  889.  
  890.    return -1;
  891. }
  892.  
  893. int OtclClass::instantiate (Tcl_Interp *interp, int argc, char *argv[],
  894.                             OtclObjMgr *otclom)
  895. {
  896.    OtclObject *otclo = new OtclObject();
  897.  
  898.    char *symbolicRef = otclom->manageObject(otclo,interp);
  899.    if (symbolicRef == NULL)
  900.    {
  901.       Otcl::setTclResult(interp,COULDNT_MANAGE_OBJECT_ERR,argv[1]);
  902.       delete otclo;
  903.       return TCL_ERROR;
  904.    }
  905.  
  906.    char *sr = strdup(symbolicRef);
  907.    
  908.    otclo->setSelf(sr);
  909.  
  910.    int returnCode = TCL_OK;
  911.    instantiatePart(interp,&returnCode,argc,argv,otclo,otclo->getPartPtrPtr());
  912.    if (returnCode != TCL_OK)
  913.    {
  914.       otclom->unManageObject(sr,interp);
  915.       // Think I may need to clean up through the parts as well without
  916.       // executing the destructor's
  917.       delete otclo;
  918.       free(sr);
  919.       return returnCode;
  920.    }
  921.  
  922.    Tcl_SetResult(interp,sr,TCL_VOLATILE);
  923.    free(sr);
  924.    return TCL_OK;
  925. }
  926.  
  927. OtclPart *OtclClassOtcl::instantiatePart (Tcl_Interp *interp,
  928.                                           int *returnCode,
  929.                                           int argc, char *argv[], OtclObject *o,
  930.                                           OtclPart **partPtr)
  931. {
  932.    return new OtclPartOtcl(interp,returnCode,argc,argv,this,o,partPtr);
  933. }
  934.  
  935. OtclClass *OtclClassOtcl::giveSuperclass (int s)
  936. {
  937.    // Dosn't check as call should be from trusted client!
  938.  
  939.    if (s < 0 || s >= noOfSuperclasses)
  940.    {
  941.       return NULL;
  942.    }
  943.    return superclass[s];
  944. }
  945.  
  946. void OtclClassOtcl::instantiateInstanceAttributes (Tcl_HashTable *hash,
  947.                                                    Tcl_Interp *interp)
  948. {
  949.    Tcl_HashEntry *entry;
  950.    Tcl_HashEntry *newEntry;
  951.    int dummy;
  952.    Tcl_HashSearch search;
  953.    OtclAttributeTemplate *otclat;
  954.    for (entry = Tcl_FirstHashEntry(&instanceAttributeTemplates,&search);
  955.         entry != NULL;
  956.         entry = Tcl_NextHashEntry(&search))
  957.    {
  958.       otclat = (OtclAttributeTemplate*)Tcl_GetHashValue(entry);
  959.       newEntry = Tcl_CreateHashEntry(hash,
  960.                    Tcl_GetHashKey(&instanceAttributeTemplates, entry),&dummy);
  961.       Tcl_SetHashValue(newEntry,otclat->instantiate(interp,newEntry));
  962.    }
  963. }
  964.  
  965. void OtclClassOtcl::createClassScope (Tcl_Interp *tclInterp)
  966. {
  967.    Interp *interp = (Interp*)tclInterp;
  968.  
  969.    // Set up a new call frame
  970.    CallFrame *callFrame = new CallFrame;
  971.    Tcl_InitHashTable(&callFrame->varTable,TCL_STRING_KEYS);
  972.    callFrame->level = (interp->varFramePtr == NULL) ?
  973.                       1 : interp->varFramePtr->level + 1;
  974.    callFrame->callerPtr = interp->framePtr;
  975.    callFrame->callerVarPtr = interp->varFramePtr;
  976.    interp->framePtr = callFrame;
  977.    interp->varFramePtr = callFrame;
  978.    interp->returnCode = TCL_OK;
  979.  
  980.    // Add upvar's locating each class attribute
  981.    Tcl_HashSearch search;
  982.    Tcl_HashEntry *hashEntry;
  983.    Tcl_HashEntry *newEntry;
  984.    OtclAttribute *otcla;
  985.    Var *link;
  986.    int dummy;
  987.    for (hashEntry = Tcl_FirstHashEntry(&classAttributes,&search);
  988.         hashEntry != NULL;
  989.         hashEntry = Tcl_NextHashEntry(&search))
  990.    {
  991.       otcla = (OtclAttribute*)Tcl_GetHashValue(hashEntry);
  992.       newEntry = Tcl_CreateHashEntry(&callFrame->varTable,
  993.                                    Tcl_GetHashKey(&classAttributes,hashEntry),
  994.                                      &dummy);
  995.       link = (Var*)malloc(sizeof(Var));
  996.       link->valueLength = 0;
  997.       link->valueSpace = 0;
  998.       link->value.upvarPtr = (Var*)*otcla;
  999.       link->value.upvarPtr->refCount++;
  1000.       link->hPtr = newEntry;
  1001.       link->refCount = 0;
  1002.       link->tracePtr = NULL;
  1003.       link->searchPtr = NULL;
  1004.       link->flags = VAR_UPVAR;
  1005.       Tcl_SetHashValue(newEntry,link);
  1006.    }
  1007.  
  1008.    // Add in the local variable that allows us to tell what class scope
  1009.    char value[10];
  1010.    sprintf(value,"%lx",(long)this);
  1011.    Tcl_SetVar(tclInterp,OTCL_CLASS_VARIABLE_NAME,value,0);
  1012. }
  1013.  
  1014. void OtclClassOtcl::destroyClassScope (Tcl_Interp *tclInterp)
  1015. {
  1016.    Interp *interp = (Interp*)tclInterp;
  1017.  
  1018.    CallFrame *topFrame = interp->framePtr;
  1019.    interp->framePtr = topFrame->callerPtr;
  1020.    interp->varFramePtr = topFrame->callerVarPtr;
  1021.  
  1022.    // Blow away all local variables
  1023.    // Code Taken from TclDeleteVars in tclVar.c from Tcl7.3 distribution
  1024.  
  1025.    // Starts Here
  1026.    Tcl_HashTable *tablePtr = &topFrame->varTable;
  1027.    Tcl_HashSearch search;
  1028.    Tcl_HashEntry *hPtr;
  1029.    Var *varPtr;
  1030.    Var *upvarPtr;
  1031.    int flags;
  1032.    ActiveVarTrace *activePtr;
  1033.  
  1034.    flags = TCL_TRACE_UNSETS;
  1035.    if (tablePtr == &interp->globalTable) {
  1036.        flags |= TCL_INTERP_DESTROYED | TCL_GLOBAL_ONLY;
  1037.    }
  1038.    for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL;
  1039.         hPtr = Tcl_NextHashEntry(&search)) {
  1040.  
  1041.       varPtr = (Var *) Tcl_GetHashValue(hPtr);
  1042.  
  1043.       /*
  1044.        * For global/upvar variables referenced in procedures, decrement
  1045.        * the reference count on the variable referred to, and free up
  1046.        * the referenced variable if it's no longer needed.
  1047.        */
  1048.  
  1049.       if (varPtr->flags & VAR_UPVAR)
  1050.       {
  1051.           upvarPtr = varPtr->value.upvarPtr;
  1052.           upvarPtr->refCount--;
  1053.  
  1054.           if ((upvarPtr->flags & VAR_UNDEFINED) && (upvarPtr->refCount == 0)
  1055.               && (upvarPtr->tracePtr == NULL))
  1056.           {
  1057.              if (upvarPtr->hPtr != NULL)
  1058.              {
  1059.                 Tcl_DeleteHashEntry(upvarPtr->hPtr);
  1060.              }
  1061.              ckfree((char *) upvarPtr);
  1062.           }
  1063.       }
  1064.  
  1065.       /*
  1066.        * Invoke traces on the variable that is being deleted, then
  1067.        * free up the variable's space (no need to free the hash entry
  1068.        * here, unless we're dealing with a global variable:  the
  1069.        * hash entries will be deleted automatically when the whole
  1070.        * table is deleted).
  1071.        */
  1072.  
  1073.        if (varPtr->tracePtr != NULL)
  1074.        {
  1075.           Otcl::callTraces(interp, (Var *) NULL, varPtr,
  1076.                            Tcl_GetHashKey(tablePtr, hPtr),(char *)NULL, flags);
  1077.            while (varPtr->tracePtr != NULL)
  1078.            {
  1079.               VarTrace *tracePtr = varPtr->tracePtr;
  1080.               varPtr->tracePtr = tracePtr->nextPtr;
  1081.               ckfree((char *) tracePtr);
  1082.            }
  1083.            for (activePtr = interp->activeTracePtr; activePtr != NULL;
  1084.                 activePtr = activePtr->nextPtr)
  1085.            {
  1086.               if (activePtr->varPtr == varPtr)
  1087.               {
  1088.                  activePtr->nextTracePtr = NULL;
  1089.               }
  1090.            }
  1091.         }
  1092.         if (varPtr->flags & VAR_ARRAY)
  1093.         {
  1094.            Otcl::deleteArray(interp,Tcl_GetHashKey(tablePtr,hPtr),varPtr,flags);
  1095.         }
  1096.         if (varPtr->valueSpace > 0)
  1097.         {
  1098.            /*
  1099.             * SPECIAL TRICK:  it's possible that the interpreter's result
  1100.             * currently points to this variable (for example, a "set" or
  1101.             * "lappend" command was the last command in a procedure that's
  1102.             * being returned from).  If this is the case, then just pass
  1103.             * ownership of the value string to the Tcl interpreter.
  1104.             */
  1105.  
  1106.            if (interp->result == varPtr->value.string)
  1107.            {
  1108.               interp->freeProc = (Tcl_FreeProc *) free;
  1109.            }
  1110.            else
  1111.            {
  1112.               ckfree(varPtr->value.string);
  1113.            }
  1114.            varPtr->valueSpace = 0;
  1115.         }
  1116.         varPtr->hPtr = NULL;
  1117.         varPtr->tracePtr = NULL;
  1118.         varPtr->flags = VAR_UNDEFINED;
  1119.         if (varPtr->refCount == 0)
  1120.         {
  1121.             ckfree((char *) varPtr);
  1122.         }
  1123.     }
  1124.     Tcl_DeleteHashTable(tablePtr);
  1125.     // Ends Here
  1126.  
  1127.    delete topFrame;
  1128. }
  1129.  
  1130. OtclConstructorMethod *OtclClassOtcl::giveConstructorMethod (void)
  1131. {
  1132.    return otclConstructorMethod;
  1133. }
  1134.  
  1135. OtclDestructorMethod *OtclClassOtcl::giveDestructorMethod (void)
  1136. {
  1137.    return otclDestructorMethod;
  1138. }
  1139.  
  1140. OtclInstanceMethod *OtclClassOtcl::giveInstanceMethod (char *mName)
  1141. {
  1142.    Tcl_HashEntry *hashEntry = Tcl_FindHashEntry(&instanceMethods,mName);
  1143.    if (hashEntry != NULL)
  1144.    {
  1145.       return (OtclInstanceMethod*)Tcl_GetHashValue(hashEntry);
  1146.    }
  1147.  
  1148.    return NULL;
  1149. }
  1150.  
  1151. int OtclClassOtcl::isComplete (void)
  1152. {
  1153.    return complete;
  1154. }
  1155.  
  1156. int OtclClassOtcl::validMethodName (char *n)
  1157. {
  1158.    if (strcmp(n,OTCL_CONSTRUCTOR_METHOD_NAME) == 0)
  1159.    {
  1160.       return OTCL_FALSE;
  1161.    }
  1162.    if (strcmp(n,OTCL_DESTRUCTOR_METHOD_NAME) == 0)
  1163.    {
  1164.       return OTCL_FALSE;
  1165.    }
  1166.    return OTCL_TRUE;
  1167. }
  1168.  
  1169. OtclClassCpp::OtclClassCpp (char *name) :
  1170.    OtclClass(name)
  1171. {
  1172.    // Place this object on the list of all OtclClassCpp objects
  1173.    next = NULL;
  1174.    if (tail == NULL)
  1175.    {
  1176.       head = this;
  1177.    }
  1178.    else
  1179.    {
  1180.       tail->next = this;
  1181.    }
  1182.    tail = this;
  1183. }
  1184.  
  1185. OtclClassCpp::~OtclClassCpp ()
  1186. {
  1187.    // Remove this object from this list of all OtclClassCpp objects
  1188.    OtclClassCpp *current = head;
  1189.    OtclClassCpp *previous = NULL;
  1190.    while (current != this)
  1191.    {
  1192.       previous = current;
  1193.       current = current->next;
  1194.    }
  1195.    if (previous != NULL)
  1196.    {
  1197.       previous->next = next;
  1198.    }
  1199.    if (head == this)
  1200.    {
  1201.       head = next;
  1202.    }
  1203.    if (tail == this)
  1204.    {
  1205.       tail = previous;
  1206.    }
  1207. }
  1208.  
  1209. int OtclClassCpp::shouldDelete (void)
  1210. {
  1211.    return OTCL_FALSE;
  1212. }
  1213.  
  1214. void OtclClassCpp::registerWithOtcl (Otcl *otcl)
  1215. {
  1216.    OtclClassCpp *current = head;
  1217.    while (current != NULL)
  1218.    {
  1219.       otcl->registerOtclClassCpp(current);
  1220.       current = current->next;
  1221.    }
  1222. }
  1223.  
  1224. OtclPart *OtclClassCpp::instantiatePart (Tcl_Interp *,
  1225.                                          int *returnCode,
  1226.                                          int , char *[], OtclObject *,
  1227.                                          OtclPart **)
  1228. {
  1229.    // Each CPP class specialises this to create an instance of the
  1230.    // appropriate OtclClassCpp C++ class with the constructor
  1231.    // from the argc and argvs....
  1232.    *returnCode = TCL_OK;
  1233.    return NULL;
  1234. }
  1235.  
  1236. int OtclClassCpp::isComplete (void)
  1237. {
  1238.    return OTCL_TRUE;
  1239. }
  1240.